<script setup lang="ts">
import { computed, getCurrentInstance, onMounted, useTemplateRef } from 'vue';
import { useVModel } from '@vueuse/core';
import type { FormInstance } from 'element-plus';
import { getAuthorization } from '@/service/request/shared';
import { isArray } from '@/utils/is';

type Config = {
  [key: string]: any;
};

const props = withDefaults(
  defineProps<{
    modelValue: Config;
    config: Config[];
    gutter?: number;
    span?: number;
    labelFormConfig?: Config;
  }>(),
  {
    gutter: 24,
    span: 24,
    labelFormConfig: () => ({
      labelWidth: 'auto'
    })
  }
);
const emit = defineEmits<{
  (e: 'update:modelValue', value: any): void; // 将 'any' 替换为实际的 modelValue 类型
}>();

const model = useVModel(props, 'modelValue', emit);

const MyFormRef = useTemplateRef<FormInstance>('MyFormRef');
const instance = getCurrentInstance();
const safeHeaders = computed(() => getAuthorization() || {});
const imgApiUrl = computed(() => import.meta.env.VITE_HTTP_IMGURL);

onMounted(() => {
  if (instance?.exposed && MyFormRef.value?.$.exposed) {
    Object.assign(instance.exposed, MyFormRef.value.$.exposed);
  } else {
    console.error('Component instance or MyFormRef is not properly exposed or initialized.');
  }
});
defineExpose(instance && instance.exposed ? { ...instance.exposed } : {});
</script>

<template>
  <ElForm v-bind="labelFormConfig" ref="MyFormRef" :model="model">
    <ElRow :gutter="gutter">
      <ElCol v-for="item in config" :key="item.key" :span="span">
        <ElFormItem v-bind="item" :prop="item.key">
          <template v-if="item.classify === 'input'">
            <ElInput v-if="item.type !== 'number'" v-model="model[item.key]" v-bind="item" />
            <ElInput v-else v-model.number="model[item.key]" v-bind="item" />
          </template>
          <ElSelect v-else-if="item.classify === 'select'" v-model="model[item.key]" v-bind="item">
            <ElOption v-for="option in item.options" v-bind="option" :key="option.value" />
          </ElSelect>
          <ElTreeSelect v-else-if="item.classify === 'treeSelect'" v-model="model[item.key]" v-bind="item" />
          <ElCheckboxGroup v-else-if="item.classify === 'checkbox'" v-model="model[item.key]" v-bind="item">
            <ElCheckbox v-for="option in item.options" v-bind="option" :key="option.value" />
          </ElCheckboxGroup>
          <ElRadioGroup v-else-if="item.classify === 'radio'" v-model="model[item.key]" v-bind="item">
            <ElRadio v-for="option in item.options" v-bind="option" :key="option.value"></ElRadio>
          </ElRadioGroup>
          <ElDatePicker v-else-if="item.classify === 'date'" v-model="model[item.key]" v-bind="item" class="w-full" />
          <ElSwitch v-else-if="item.classify === 'switch'" v-model="model[item.key]" v-bind="item" />
          <ElUpload
            v-else-if="item.classify === 'upload'"
            v-model="model[item.key]"
            :action="imgApiUrl"
            :headers="safeHeaders"
            name="files"
            v-bind="item"
            :on-success="
              (response: any) =>
                (model[item.key] = isArray(model[item.key])
                  ? [...model[item.key], response?.data[0]]
                  : response?.data[0])
            "
            class="avatar-uploader"
          >
            <img v-if="model[item.key]" :src="model[item.key]" class="avatar" />
            <ElIcon v-else class="avatar-uploader-icon">
              <SvgIcon icon="add" class="text-30px" />
            </ElIcon>
          </ElUpload>
        </ElFormItem>
      </ElCol>
    </ElRow>
  </ElForm>
</template>

<style>
.avatar-uploader .avatar {
  display: block;
  width: 88px;
  height: 88px;
}

.avatar-uploader .el-upload {
  position: relative;
  overflow: hidden;
  cursor: pointer;
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  width: 178px;
  height: 178px;
  font-size: 28px;
  color: #8c939d;
  text-align: center;
}
</style>
